﻿#region Header

// <file>
//     <copyright see="prj:///doc/copyright.txt"/>
//     <license see="prj:///doc/license.txt"/>
//     <owner name="Mike Krüger" email="mike@icsharpcode.net"/>
//     <version>$Revision: 2533 $</version>
// </file>

#endregion Header

namespace ICSharpCode.TextEditor.Document
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.IO;

    public class HighlightingManager
    {
        #region Fields

        static HighlightingManager highlightingManager;

        Hashtable extensionsToName = new Hashtable();

        // hash table from extension name to highlighting definition,
        // OR from extension name to Pair SyntaxMode,ISyntaxModeFileProvider
        Hashtable highlightingDefs = new Hashtable();
        ArrayList syntaxModeFileProviders = new ArrayList();

        #endregion Fields

        #region Constructors

        static HighlightingManager()
        {
            highlightingManager = new HighlightingManager();
            highlightingManager.AddSyntaxModeFileProvider(new ResourceSyntaxModeProvider());
        }

        public HighlightingManager()
        {
            CreateDefaultHighlightingStrategy();
        }

        #endregion Constructors

        #region Events

        public event EventHandler ReloadSyntaxHighlighting;

        #endregion Events

        #region Properties

        public static HighlightingManager Manager
        {
            get {
                return highlightingManager;
            }
        }

        public DefaultHighlightingStrategy DefaultHighlighting
        {
            get {
                return (DefaultHighlightingStrategy)highlightingDefs["Default"];
            }
        }

        public Hashtable HighlightingDefinitions
        {
            get {
                return highlightingDefs;
            }
        }

        #endregion Properties

        #region Methods

        public void AddHighlightingStrategy(IHighlightingStrategy highlightingStrategy)
        {
            highlightingDefs[highlightingStrategy.Name] = highlightingStrategy;
            foreach (string extension in highlightingStrategy.Extensions)
            {
                extensionsToName[extension.ToUpperInvariant()] = highlightingStrategy.Name;
            }
        }

        public void AddSyntaxModeFileProvider(ISyntaxModeFileProvider syntaxModeFileProvider)
        {
            foreach (SyntaxMode syntaxMode in syntaxModeFileProvider.SyntaxModes) {
                highlightingDefs[syntaxMode.Name] = new DictionaryEntry(syntaxMode, syntaxModeFileProvider);
                foreach (string extension in syntaxMode.Extensions) {
                    extensionsToName[extension.ToUpperInvariant()] = syntaxMode.Name;
                }
            }
            if (!syntaxModeFileProviders.Contains(syntaxModeFileProvider)) {
                syntaxModeFileProviders.Add(syntaxModeFileProvider);
            }
        }

        public IHighlightingStrategy FindHighlighter(string name)
        {
            object def = highlightingDefs[name];
            if (def is DictionaryEntry) {
                return LoadDefinition((DictionaryEntry)def);
            }
            return def == null ? DefaultHighlighting : (IHighlightingStrategy)def;
        }

        public IHighlightingStrategy FindHighlighterForFile(string fileName)
        {
            string highlighterName = (string)extensionsToName[Path.GetExtension(fileName).ToUpperInvariant()];
            if (highlighterName != null) {
                object def = highlightingDefs[highlighterName];
                if (def is DictionaryEntry) {
                    return LoadDefinition((DictionaryEntry)def);
                }
                return def == null ? DefaultHighlighting : (IHighlightingStrategy)def;
            } else {
                return DefaultHighlighting;
            }
        }

        public void ReloadSyntaxModes()
        {
            highlightingDefs.Clear();
            extensionsToName.Clear();
            CreateDefaultHighlightingStrategy();
            foreach (ISyntaxModeFileProvider provider in syntaxModeFileProviders) {
                provider.UpdateSyntaxModeList();
                AddSyntaxModeFileProvider(provider);
            }
            OnReloadSyntaxHighlighting(EventArgs.Empty);
        }

        internal KeyValuePair<SyntaxMode, ISyntaxModeFileProvider> FindHighlighterEntry(string name)
        {
            foreach (ISyntaxModeFileProvider provider in syntaxModeFileProviders) {
                foreach (SyntaxMode mode in provider.SyntaxModes) {
                    if (mode.Name == name) {
                        return new KeyValuePair<SyntaxMode, ISyntaxModeFileProvider>(mode, provider);
                    }
                }
            }
            return new KeyValuePair<SyntaxMode, ISyntaxModeFileProvider>(null, null);
        }

        protected virtual void OnReloadSyntaxHighlighting(EventArgs e)
        {
            if (ReloadSyntaxHighlighting != null) {
                ReloadSyntaxHighlighting(this, e);
            }
        }

        void CreateDefaultHighlightingStrategy()
        {
            DefaultHighlightingStrategy defaultHighlightingStrategy = new DefaultHighlightingStrategy();
            defaultHighlightingStrategy.Extensions = new string[] {};
            defaultHighlightingStrategy.Rules.Add(new HighlightRuleSet());
            highlightingDefs["Default"] = defaultHighlightingStrategy;
        }

        IHighlightingStrategy LoadDefinition(DictionaryEntry entry)
        {
            SyntaxMode              syntaxMode             = (SyntaxMode)entry.Key;
            ISyntaxModeFileProvider syntaxModeFileProvider = (ISyntaxModeFileProvider)entry.Value;

            DefaultHighlightingStrategy highlightingStrategy = null;
            try {
                highlightingStrategy = HighlightingDefinitionParser.Parse(syntaxMode, syntaxModeFileProvider.GetSyntaxModeFile(syntaxMode));
                if (highlightingStrategy.Name != syntaxMode.Name) {
                    throw new HighlightingDefinitionInvalidException("The name specified in the .xshd '" + highlightingStrategy.Name + "' must be equal the syntax mode name '" + syntaxMode.Name + "'");
                }
            } finally {
                if (highlightingStrategy == null) {
                    highlightingStrategy = DefaultHighlighting;
                }
                highlightingDefs[syntaxMode.Name] = highlightingStrategy;
                highlightingStrategy.ResolveReferences();
            }
            return highlightingStrategy;
        }

        #endregion Methods
    }
}